home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / kms20src.lha / KMSS / serverrexx.c < prev    next >
C/C++ Source or Header  |  1995-05-07  |  33KB  |  1,163 lines

  1. /**********************************
  2.  *              KMS               *
  3.  **********************************
  4.  *  ©1992 by BlackMagic Software  *
  5.  **********************************
  6.  *                                *
  7.  **********************************/
  8.  
  9. #include <KMS/KMS.h>
  10. #include <KMS/KMS_rexx.h>
  11. #include <KMS/KMS_devlib.h>
  12.  
  13. Prototype VOID KMSRexxDisp(struct RexxMsg *, struct rexxCommandList *, STRPTR);
  14. Prototype VOID RexxErr(UWORD);
  15. Prototype VOID RexxOK(STRPTR, STRPTR);
  16. Prototype VOID Rexx_GETKMSGC(struct RexxMsg *, LONG []);
  17. Prototype VOID Rexx_SHUTDOWN(struct RexxMsg *, LONG []);
  18. Prototype VOID Rexx_LOCKPORT(struct RexxMsg *, LONG []);
  19. Prototype VOID Rexx_UNLOCKPORT(struct RexxMsg *, LONG []);
  20. Prototype VOID Rexx_SAVESYS(struct RexxMsg *, LONG []);
  21. Prototype VOID Rexx_LOGENTRY(struct RexxMsg *, LONG []);
  22. Prototype VOID Rexx_EXPIRE(struct RexxMsg *, LONG []);
  23. Prototype VOID Rexx_REFRESH(struct RexxMsg *, LONG []);
  24. Prototype VOID SendPortCmd(STRPTR);
  25. Prototype VOID RexxCmdParse(STRPTR, UBYTE *, STRPTR *);
  26. Prototype BOOL CheckStack(VOID);
  27. Prototype struct LocalConfig *GetKMSLC(struct RexxMsg *);
  28. Prototype struct AreaNode *AreaSearch(STRPTR);
  29. Prototype VOID TakeMSem(BOOL);
  30. Prototype VOID DropMSem(VOID);
  31. Prototype VOID TakeASem(BOOL);
  32. Prototype VOID DropASem(VOID);
  33.  
  34. extern LONG SetMode(BPTR, LONG);
  35. extern LONG IsInteractive(BPTR);
  36.  
  37. extern VOID KPrintF(APTR, ...);
  38.  
  39. /***********************************
  40.  * Globale Variable                *
  41.  ***********************************/
  42.  
  43. extern struct KMSBase *KMSBase;
  44.  
  45. extern ULONG RexxSignal;
  46. extern UMSAccount SysUMSAccount;
  47. extern UBYTE ShutDown;
  48.  
  49. struct LocalConfig *KMS_LC = NULL;
  50.  
  51. /* Liste implementierter Kommandos (lower case!) */
  52.  
  53. struct rexxCommandList RCL[] =
  54.    {
  55.    {"getkmsgc",   (APTR)&Rexx_GETKMSGC,   ""},
  56.    {"shutdown",   (APTR)&Rexx_SHUTDOWN,   "DELAY/K/N,UMS/S"},
  57.    {"lockport",   (APTR)&Rexx_LOCKPORT,   "DELAY/K/N"},
  58.    {"unlockport", (APTR)&Rexx_UNLOCKPORT, ""},
  59.    {"savesys",    (APTR)&Rexx_SAVESYS,    ""},
  60.    {"logentry",   (APTR)&Rexx_LOGENTRY,   "TEXT/F"},
  61.    {"expire",     (APTR)&Rexx_EXPIRE,     "QUIET/S,RESET/S,UNLISTED/S"},
  62.    {"refresh",    (APTR)&Rexx_REFRESH,    "SYSTEM/S,ALL/S,UMSGLOBAL/S"},
  63.    {NULL, NULL, NULL}
  64.    };
  65.  
  66. #define ERR_INVALID_PARAMS              1
  67. #define ERR_TOO_MANY_PARAMS             2
  68. #define ERR_ALREADY_LOCKED              3
  69. #define ERR_NOT_LOCKED                  4
  70. #define ERR_TOO_FEW_PARAMS              5
  71. #define ERR_NO_LOGIN                    6
  72. #define ERR_USER_ACTIVE                 7
  73. #define ERR_INVALID_PASSWORD            8
  74. #define ERR_NO_SUCH_USER                9
  75. #define ERR_NO_SUCH_UMS_USER            10
  76. #define ERR_NO_MSG_READ                 11
  77. #define ERR_UMS_READ_ERROR              12
  78. #define ERR_SHUTDOWN                    13
  79. #define ERR_NO_VARNAME                  14
  80. #define ERR_VARNAME_TOO_LONG            15
  81. #define ERR_TIMEOUT                     16
  82. #define ERR_OUT_OF_MEMORY               17
  83. #define ERR_ONLY_CURRENT_PWD            18
  84. #define ERR_FILE_NOT_FOUND              19
  85.  
  86. STRPTR RexxErrStr[20] =
  87.    {
  88.    "",
  89.    " 1: Invalid parameters",
  90.    " 2: Too many parameters",
  91.    " 3: Port already locked",
  92.    " 4: Port is not locked",
  93.    " 5: Too few parameters",
  94.    " 6: No user logged in",
  95.    " 7: A user is already logged in",
  96.    " 8: Invalid password",
  97.    " 9: No such user registered",
  98.    "10: No such user in UMS.CONFIG",
  99.    "11: No msg active",
  100.    "12: UMS read error",
  101.    "13: System shutting down",
  102.    "14: No stemname set",
  103.    "15: Name too long",
  104.    "16: User timed out",
  105.    "17: Out of memory",
  106.    "18: Only password of current user available",
  107.    "19: File not found"
  108.    };
  109.  
  110. UBYTE KMSRexx = 0;
  111.  
  112. static STRPTR KMSRexxStr;
  113. static STRPTR KMSRexxVar;
  114. static ULONG KMSRexxRes;
  115. static UBYTE KMSRexxErr;
  116.  
  117. /*******************************************
  118.  * Rexx-"Dispatch"-Funktion                *
  119.  * -> Ausfuehrung interner Rexx-Befehle    *
  120.  * Vorsicht!: Bei rekursiven Aufrufen      *
  121.  * ist diese Prozedur sehr Stack-intensiv! *
  122.  *******************************************
  123.  * I: RexxMsg, CommandList, Argumente      *
  124.  * O: ---                                  *
  125.  *******************************************/
  126.  
  127. /// "KMSRexxDisp"
  128.  
  129. static VOID (*funktion)(struct RexxMsg *, STRPTR, UBYTE, STRPTR *);
  130. static VOID (*readargfunc)(struct RexxMsg *, LONG[]);
  131.  
  132. VOID KMSRexxDisp(struct RexxMsg *msg, struct rexxCommandList *dat, STRPTR p)
  133.    {
  134.    KMSRexxStr = NULL;
  135.    KMSRexxVar = NULL;
  136.    KMSRexxRes = 0;
  137.    KMSRexxErr = 0;
  138.  
  139.    if(CheckStack())
  140.       {
  141.       KMSRexx++;
  142.  
  143.       if (dat->template)
  144.          {
  145.          LONG rxargv[REXXCMDARGS];
  146.          struct RDArgs *rda;
  147.          STRPTR parsebuff;
  148.          UWORD n;
  149.  
  150.          for(n = 0; n < REXXCMDARGS; n++)
  151.             rxargv[n] = NULL;
  152.    
  153.          parsebuff = malloc(strlen(p) + 2);
  154.          if (parsebuff)
  155.             {
  156.             strcpy(parsebuff, p);
  157.             strcat(parsebuff, "\n");
  158.  
  159.             rda = AllocDosObjectTags(DOS_RDARGS, TAG_DONE);
  160.             if (rda)
  161.                {
  162.                rda->RDA_ExtHelp = NULL;
  163.                rda->RDA_Source.CS_Buffer = parsebuff;
  164.                rda->RDA_Source.CS_Length = strlen(parsebuff) + 1;
  165.  
  166.                if (rda = ReadArgs(dat->template, rxargv, rda))
  167.                   {
  168.                   KMS_LC = GetKMSLC(msg);
  169.                                     /* LocalConfig des Befehlsgebers ermitteln */
  170.                                     /* Ist NULL, wenn Befehl nicht von Client */
  171.  
  172.                   readargfunc = dat->userdata;
  173.                   readargfunc(msg, rxargv);
  174.       
  175.                   FreeArgs(rda);
  176.                   }
  177.                else
  178.                   {
  179.                   KMSRexxErr = ERR_INVALID_PARAMS;
  180.                   KMSRexxRes = 20;
  181.                   }
  182.  
  183.                FreeDosObject(DOS_RDARGS, rda);
  184.                }
  185.             else
  186.                {
  187.                KMSRexxErr = ERR_OUT_OF_MEMORY;
  188.                KMSRexxRes = 20;
  189.                }
  190.             
  191.             free(parsebuff);
  192.             }
  193.          else
  194.             {
  195.             KMSRexxErr = ERR_OUT_OF_MEMORY;
  196.             KMSRexxRes = 20;
  197.             }
  198.          }
  199.       else
  200.          {
  201.          STRPTR *argv[MAXCMDARGS];
  202.          STRPTR rexxbuff;
  203.          UBYTE argc;
  204.  
  205.          rexxbuff = malloc(LEN_REXXBUFF+1);
  206.          if (!rexxbuff)
  207.             {
  208.             KMSRexxErr = ERR_OUT_OF_MEMORY;
  209.             KMSRexxRes = 20;
  210.             }
  211.          else
  212.             {
  213.             strcpy(rexxbuff, dat->name);
  214.             strncat(rexxbuff, p, LEN_REXXBUFF-strlen(rexxbuff));
  215.             rexxbuff[LEN_REXXBUFF] = '\0';
  216.  
  217.             argc = 0;
  218.             RexxCmdParse(rexxbuff, &argc, argv); /* Kommando tokenisieren */
  219.  
  220.             KMS_LC = GetKMSLC(msg); /* LocalConfig des Befehlsgebers ermitteln */
  221.                                     /* Ist NULL, wenn Befehl nicht von Client */
  222.  
  223.             funktion = dat->userdata;
  224.             funktion(msg, p, argc, argv);
  225.  
  226.             RexxCmdParse(NULL, &argc, argv); /* Token freigeben */
  227.  
  228.             free(rexxbuff);
  229.             }
  230.          }
  231.  
  232.       KMSRexx--;
  233.       }
  234.    else
  235.       {
  236.       KMSRexxErr = ERR_OUT_OF_MEMORY;
  237.       KMSRexxRes = 20;
  238.       }
  239.  
  240.    if(KMSRexxErr)
  241.       SetARexxLastError(msg, RexxErrStr[KMSRexxErr]);
  242.    else if(KMSRexxVar && KMSRexxStr)
  243.       SetRexxVar((struct Message *)msg, KMSRexxVar, KMSRexxStr, (ULONG)strlen(KMSRexxStr));
  244.  
  245.    replyRexxCmd(msg, KMSRexxRes, KMSRexxStr);
  246.  
  247.    if(KMSRexxStr)
  248.       free(KMSRexxStr);
  249.    if(KMSRexxVar)
  250.       free(KMSRexxVar);
  251.    }
  252.  
  253. ///
  254.  
  255. /***************************************
  256.  * Rexx-Fehler-RESULT-String           *
  257.  ***************************************
  258.  * I: Fehlertext                       *
  259.  * O: ---                              *
  260.  ***************************************/
  261.  
  262. /// "RexxErr"
  263.  
  264. VOID RexxErr(UWORD errnum)
  265.    {
  266.    KMSRexxErr = errnum;
  267.  
  268.    KMSRexxRes = 20;
  269.    }
  270.  
  271. ///
  272.  
  273. /***************************************
  274.  * Rexx-OK-Standard-RESULT-String      *
  275.  ***************************************
  276.  * I: Erfolgstext/-daten, Varname      *
  277.  * O: ---                              *
  278.  ***************************************/
  279.  
  280. /// "RexxOK"
  281.  
  282. VOID RexxOK(STRPTR restxt, STRPTR varname)
  283.    {
  284.    if(restxt)
  285.       KMSRexxStr = strdup(restxt);
  286.  
  287.    if(varname)
  288.       KMSRexxVar = strdup(varname);
  289.    }
  290.  
  291. ///
  292.  
  293. /***************************************
  294.  * Rexx-Kommando "GETKMSGC"            *
  295.  ***************************************
  296.  * I: Parameterstring                  *
  297.  * O: ---                              *
  298.  ***************************************/
  299.  
  300. /// "Rexx_GETKMSGC"
  301.  
  302. /* "" */
  303.  
  304. VOID Rexx_GETKMSGC(struct RexxMsg *msg, LONG rxargv[])
  305.    {
  306.    TEXT buff[LEN_NUMBER+1];
  307.  
  308.    sprintf(buff, "%ld", (ULONG)KMSBase);
  309.    RexxOK(buff, NULL);
  310.    }
  311.  
  312. ///
  313.  
  314. /***************************************
  315.  * Rexx-Kommando "SHUTDOWN"            *
  316.  ***************************************
  317.  * I: Parameterstring                  *
  318.  * O: ---                              *
  319.  ***************************************/
  320.  
  321. /// "Rexx_SHUTDOWN"
  322.  
  323. /* DELAY/K/N,UMS/S */
  324.  
  325. VOID Rexx_SHUTDOWN(struct RexxMsg *msg, LONG rxargv[])
  326.    {
  327.    TEXT buff[LEN_NUMBER+15+1];
  328.  
  329.    if (rxargv[0]) /* DELAY/K/N */
  330.       {
  331.       UWORD offset = *(UWORD *)rxargv[0];
  332.  
  333.       sprintf(buff, "SHUTDOWN DELAY %d", offset);
  334.       SendPortCmd(buff);
  335.  
  336.       ShutDown = SHUTDOWN_DELAYED;
  337.       }
  338.    else if(rxargv[1]) /* UMS/S */
  339.       {
  340.       SendPortCmd("SHUTDOWN");
  341.       ShutDown = SHUTDOWN_IMMED_SYS;
  342.       }
  343.    else
  344.       {
  345.       SendPortCmd("SHUTDOWN");
  346.  
  347.       ShutDown = SHUTDOWN_IMMEDIATE;
  348.       }
  349.    }
  350.  
  351. ///
  352.  
  353. /***************************************
  354.  * Rexx-Kommando "LOCKPORT"            *
  355.  ***************************************
  356.  * I: Parameterstring                  *
  357.  * O: ---                              *
  358.  ***************************************/
  359.  
  360. /// "Rexx_LOCKPORT"
  361.  
  362. /* DELAY/K/N */
  363.  
  364. VOID Rexx_LOCKPORT(struct RexxMsg *msg, LONG rxargv[])
  365.    {
  366.    TEXT buff[LEN_NUMBER+15+1];
  367.  
  368.    if (rxargv[0]) /* DELAY/K/N */
  369.       {
  370.       UWORD offset = *(UWORD *)rxargv[0];
  371.       sprintf(buff, "LOCKPORT DELAY %d", offset);
  372.       SendPortCmd(buff);
  373.       }
  374.    else
  375.       SendPortCmd("LOCKPORT");
  376.    }
  377.  
  378. ///
  379.  
  380. /***************************************
  381.  * Rexx-Kommando "UNLOCKPORT"          *
  382.  ***************************************
  383.  * I: Parameterstring                  *
  384.  * O: ---                              *
  385.  ***************************************/
  386.  
  387. /// "Rexx_UNLOCKPORT"
  388.  
  389. /* "" */
  390.  
  391. VOID Rexx_UNLOCKPORT(struct RexxMsg *msg, LONG rxargv[])
  392.    {
  393.    SendPortCmd("UNLOCKPORT");
  394.    }
  395.  
  396. ///
  397.  
  398. /***************************************
  399.  * Rexx-Kommando "SAVESYS"             *
  400.  ***************************************
  401.  * I: Parameterstring                  *
  402.  * O: ---                              *
  403.  ***************************************/
  404.  
  405. /// "Rexx_SAVESYS"
  406.  
  407. /* "" */
  408.  
  409. VOID Rexx_SAVESYS(struct RexxMsg *msg, LONG rxargv[])
  410.    {
  411.    SaveData();
  412.    }
  413.  
  414. ///
  415.  
  416. /***************************************
  417.  * Rexx-Kommando "LOGENTRY"            *
  418.  ***************************************
  419.  * I: Parameterstring                  *
  420.  * O: ---                              *
  421.  ***************************************/
  422.  
  423. /// "Rexx_LOGENTRY"
  424.  
  425. /* TEXT/F */
  426.  
  427. VOID Rexx_LOGENTRY(struct RexxMsg *msg, LONG rxargv[])
  428.    {
  429.    FILE *logfile;
  430.    TEXT timeinfo[19];
  431.    TEXT logline[LEN_MAXLINE+1];
  432.    TEXT target[LEN_NUMBER+4+1];
  433.    TEXT intext[LEN_LOGLINE+1];
  434.    TEXT dosbuff[LEN_DOSPATH+1];
  435.    UBYTE loglevel = 9;
  436.  
  437.    if (!rxargv[0]) /* TEXT/F */
  438.       {
  439.       strcpy(dosbuff, KMSBase->LogDir);
  440.       strcat(dosbuff, "KMS.LOG");
  441.       logfile = fopen(dosbuff, "a");
  442.       if(logfile)
  443.          {
  444.          fputs("\n", logfile);
  445.          fclose(logfile);
  446.          }
  447.  
  448.       return;
  449.       }
  450.  
  451.    strncpy(intext, (STRPTR)rxargv[0], LEN_LOGLINE);
  452.    intext[LEN_LOGLINE] = '\0';
  453.    if(*intext >= '1' && *intext <= '9')
  454.       loglevel = (UBYTE)(*intext - '0');
  455.  
  456.    if(loglevel > KMSBase->LogLevel)
  457.       return;
  458.  
  459.    time_t zeit = time(NULL);
  460.    struct tm *zt = localtime(&zeit);
  461.    strftime(timeinfo, 18, "%d-%b-%y %H:%M:%S", zt);
  462.    if(KMS_LC)
  463.       sprintf(logline, "OUT TEXT %%G%%R%1d %s %02d%%O %s%%N", loglevel, timeinfo, KMS_LC->ID, intext+1);
  464.    else
  465.       sprintf(logline, "OUT TEXT %%G%%R%1d %s --%%O %s%%N", loglevel, timeinfo, intext+1);
  466.  
  467.    TakeMSem(FALSE);
  468.  
  469.    struct KMSNode *member = KMSBase->MemberList.mlh_Head;
  470.  
  471.    while(member->Node.mln_Succ)
  472.       {
  473.       if(member->LCPtr->OutputLog)
  474.          {
  475.          sprintf(target, "KMS.%d", member->LCPtr->ID);
  476.          sendRexxCmd(logline, NULL, NULL, NULL, NULL, target);
  477.          }
  478.  
  479.       member = member->Node.mln_Succ;
  480.       }
  481.  
  482.    DropMSem();
  483.  
  484.    /* Log-Datei */
  485.  
  486.    if(KMS_LC)
  487.       sprintf(logline, "%1d %s %02d %s\n", loglevel, timeinfo, KMS_LC->ID, intext+1);
  488.    else
  489.       sprintf(logline, "%1d %s -- %s\n", loglevel, timeinfo, intext+1);
  490.  
  491.    strcpy(dosbuff, KMSBase->LogDir);
  492.    strcat(dosbuff, "KMS.LOG");
  493.    logfile = fopen(dosbuff, "a");
  494.    if(logfile)
  495.       {
  496.       fprintf(logfile, logline);
  497.       fclose(logfile);
  498.       }
  499.    }
  500.  
  501. ///
  502.  
  503. /***************************************
  504.  * Rexx-Kommando "EXPIRE"              *
  505.  ***************************************
  506.  * I: RexxMsg, Parameterstring, Args   *
  507.  * O: ---                              *
  508.  ***************************************/
  509.  
  510. /// "Rexx_EXPIRE"
  511.  
  512. /* QUIET/S,RESET/S,UNLISTED/S */
  513.  
  514. VOID Rexx_EXPIRE(struct RexxMsg *msg, LONG rxargv[])
  515.    {
  516.    BPTR out = NULL;
  517.    TEXT buff[LEN_MAXLINE+1];
  518.    TEXT timeinfo[19];
  519.    BOOL reset = FALSE;
  520.    BOOL unlisted = FALSE;
  521.  
  522.    if(KMS_LC)
  523.       out = KMS_LC->OutHandle;
  524.    else
  525.       out = Output();
  526.  
  527.    if(rxargv[0]) /* QUIET/S */
  528.       out = NULL;
  529.    if(rxargv[1]) /* RESET/S */
  530.       reset = TRUE;
  531.    if(rxargv[2]) /* UNLISTED/S */
  532.       unlisted = TRUE;
  533.  
  534.    time_t zeit = time(NULL);
  535.    struct tm *zt = localtime(&zeit);
  536.    strftime(timeinfo, 18, "%d-%b-%y %H:%M:%S", zt);
  537.    if(out)
  538.       {
  539.       sprintf(buff, "%s\r\n", timeinfo);
  540.       Write(out, buff, strlen(buff));
  541.       }
  542.  
  543.    if(reset)
  544.       {
  545.       /* Alle Expired-Flags ruecksetzen */
  546.  
  547.       UMSSelectTags(SysUMSAccount, UMSTAG_SelReadGlobal,  TRUE,
  548.                                    UMSTAG_SelMask,        UMSGSTATF_Expired,
  549.                                    UMSTAG_SelMatch,       UMSGSTATF_Expired,
  550.                                    UMSTAG_SelWriteGlobal, TRUE,
  551.                                    UMSTAG_SelUnset,       UMSGSTATF_Expired,
  552.                                    TAG_DONE);
  553.       }
  554.  
  555.    if(unlisted)
  556.       {
  557.       if(out)
  558.          {
  559.          strcpy(buff, "\r\nExpiring unlisted UMS groups...\r\n");
  560.          Write(out, buff, strlen(buff));
  561.          }
  562.  
  563.       UMSMsgNum msgnum, num;
  564.       STRPTR areaname;
  565.  
  566.       /* Alle Local 8 rücksetzen */
  567.  
  568.       UMSSelectTags(SysUMSAccount, UMSTAG_SelWriteLocal, TRUE,
  569.                                    UMSTAG_SelUnset,      (1L<<8),
  570.                                    TAG_DONE);
  571.  
  572.       /* Für alle gelöschten Msgs Local 8 setzen */
  573.  
  574.       UMSSelectTags(SysUMSAccount, UMSTAG_SelReadGlobal,  TRUE,
  575.                                    UMSTAG_SelMask,        UMSGSTATF_Deleted,
  576.                                    UMSTAG_SelMatch,       UMSGSTATF_Deleted,
  577.                                    UMSTAG_SelWriteLocal,  TRUE,
  578.                                    UMSTAG_SelSet,         (1L<<8),
  579.                                    TAG_DONE);
  580.  
  581.       /* Solange weitere Nachricht mit nicht gesetztem Local-Flag 8 */
  582.  
  583.       msgnum = 0;
  584.       while(msgnum = UMSSearchTags(SysUMSAccount, UMSTAG_SearchLast,      msgnum,
  585.                                                   UMSTAG_SearchDirection, 1,
  586.                                                   UMSTAG_SearchLocal,     TRUE,
  587.                                                   UMSTAG_SearchMask,      (1L<<8),
  588.                                                   UMSTAG_SearchMatch,     0,
  589.                                                   TAG_DONE))
  590.          {
  591.          /* Gruppennamen besorgen */
  592.  
  593.          if(ReadUMSMsgTags(SysUMSAccount, UMSTAG_RMsgNum, msgnum,
  594.                                           UMSTAG_RGroup, &areaname,
  595.                                           TAG_DONE))
  596.             {
  597.             /* In allen Nachrichten der Gruppe Local-Flag 8 setzen */
  598.  
  599.             UMSSelectTags(SysUMSAccount, UMSTAG_WGroup,        (LONG)areaname ? (LONG)areaname : (LONG)"",
  600.                                          UMSTAG_SelWriteLocal, TRUE,
  601.                                          UMSTAG_SelSet,        (1L<<8),
  602.                                          UMSTAG_SelQuick,      TRUE,
  603.                                          TAG_DONE);
  604.  
  605.             /* Wenn Echomail-Gruppe */
  606.  
  607.             if(areaname)
  608.                {
  609.                /* Gefundene Area zum expirieren vormerken */
  610.  
  611.                if(!AreaSearch(areaname))
  612.                   {
  613.                   num = UMSSelectTags(SysUMSAccount, UMSTAG_WGroup,         (LONG)areaname,
  614.                                                      UMSTAG_SelWriteGlobal, TRUE,
  615.                                                      UMSTAG_SelSet,         UMSGSTATF_Expired,
  616.                                                      UMSTAG_SelQuick,       TRUE,
  617.                                                      TAG_DONE);
  618.  
  619.                   if(out)
  620.                      {
  621.                      sprintf(buff, "%-73.73s -%4d\r\n", areaname, num);
  622.                      Write(out, buff, strlen(buff));
  623.                      }
  624.                   }
  625.                }
  626.             }
  627.  
  628.          /* Message freigeben */
  629.  
  630.          FreeUMSMsg(SysUMSAccount, msgnum);
  631.          }
  632.       }
  633.  
  634.    if(out)
  635.       {
  636.       strcpy(buff, "\r\nExpiring KMS groups...\r\n");
  637.       Write(out, buff, strlen(buff));
  638.       }
  639.  
  640.    /* Alle Local 8 und 9 rücksetzen */
  641.  
  642.    UMSSelectTags(SysUMSAccount, UMSTAG_SelWriteLocal, TRUE,
  643.                                 UMSTAG_SelUnset,      (1L<<8)|(1L<<9),
  644.                                 TAG_DONE);
  645.  
  646.    /* Für alle archivierten Msgs Local 8 setzen */
  647.  
  648.    UMSSelectTags(SysUMSAccount, UMSTAG_SelMask,        UMSUSTATF_Archive,
  649.                                 UMSTAG_SelMatch,       UMSUSTATF_Archive,
  650.                                 UMSTAG_SelWriteLocal,  TRUE,
  651.                                 UMSTAG_SelSet,         (1L<<8),
  652.                                 TAG_DONE);
  653.  
  654.    /* Für alle gelöschten Msgs Local 9 setzen */
  655.  
  656.    UMSSelectTags(SysUMSAccount, UMSTAG_SelReadGlobal,  TRUE,
  657.                                 UMSTAG_SelMask,        UMSGSTATF_Deleted,
  658.                                 UMSTAG_SelMatch,       UMSGSTATF_Deleted,
  659.                                 UMSTAG_SelWriteLocal,  TRUE,
  660.                                 UMSTAG_SelSet,         (1L<<9),
  661.                                 TAG_DONE);
  662.  
  663.    /* Alle Areas durchgehen */
  664.  
  665.    TakeASem(FALSE);
  666.  
  667.    struct AreaNode *apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  668.  
  669.    while(apoint->Node.mln_Succ)
  670.       {
  671.       UMSMsgNum count, arch, zaehl;
  672.       UMSMsgNum hold = apoint->AreaData.HoldNum;
  673.       UMSMsgNum num = 0;
  674.       UMSMsgNum del = 0;
  675.  
  676.       /* Alle gesetzten Local 2 rücksetzen */
  677.  
  678.       UMSSelectTags(SysUMSAccount, UMSTAG_SelReadLocal,  TRUE,
  679.                                    UMSTAG_SelMask,       (1L<<2),
  680.                                    UMSTAG_SelMatch,      (1L<<2),
  681.                                    UMSTAG_SelWriteLocal, TRUE,
  682.                                    UMSTAG_SelUnset,      (1L<<2),
  683.                                    TAG_DONE);
  684.  
  685.       /* Alle Nachrichten in aktueller Gruppe mit Local 2 markieren */
  686.  
  687.       count =
  688.       UMSSelectTags(SysUMSAccount, UMSTAG_WGroup,        apoint->AreaData.MBName,
  689.                                    UMSTAG_SelWriteLocal, TRUE,
  690.                                    UMSTAG_SelSet,        (1L<<2),
  691.                                    UMSTAG_SelQuick,      TRUE,
  692.                                    TAG_DONE);
  693.  
  694.       /* Für alle gelöschten Msgs Local 2 wieder löschen */
  695.  
  696.       count -=
  697.       UMSSelectTags(SysUMSAccount, UMSTAG_SelReadLocal,  TRUE,
  698.                                    UMSTAG_SelMask,       (1L<<2)|(1L<<9),
  699.                                    UMSTAG_SelMatch,      (1L<<2)|(1L<<9),
  700.                                    UMSTAG_SelWriteLocal, TRUE,
  701.                                    UMSTAG_SelUnset,      (1L<<2),
  702.                                    TAG_DONE);
  703.  
  704.       /* Für alle archivierten Msgs Local 2 wieder löschen */
  705.  
  706.       arch =
  707.       UMSSelectTags(SysUMSAccount, UMSTAG_SelReadLocal,  TRUE,
  708.                                    UMSTAG_SelMask,       (1L<<2)|(1L<<8),
  709.                                    UMSTAG_SelMatch,      (1L<<2)|(1L<<8),
  710.                                    UMSTAG_SelWriteLocal, TRUE,
  711.                                    UMSTAG_SelUnset,      (1L<<2),
  712.                                    TAG_DONE);
  713.  
  714.       /* Anzahl maximal zu löschender Nachrichten berechnen */
  715.  
  716.       if(hold > 0 && count - arch > hold)
  717.          del = count - arch - hold;
  718.  
  719.       /* Jetzt <del> Nachrichten zum löschen freigeben */
  720.  
  721.       if(del)
  722.          {
  723.          for(zaehl = 1; zaehl <= del; zaehl++)
  724.             {
  725.             num =
  726.             UMSSearchTags(SysUMSAccount, UMSTAG_SearchLast,      num,
  727.                                          UMSTAG_SearchDirection, 1,
  728.                                          UMSTAG_SearchLocal,     TRUE,
  729.                                          UMSTAG_SearchMask,      (1L<<2),
  730.                                          UMSTAG_SearchMatch,     (1L<<2),
  731.                                          TAG_DONE);
  732.  
  733.             if(num)
  734.                {
  735.                /* Expired-Flag setzen */
  736.  
  737.                UMSSelectTags(SysUMSAccount, UMSTAG_SelMsg,         num,
  738.                                             UMSTAG_SelWriteGlobal, TRUE,
  739.                                             UMSTAG_SelSet,         UMSGSTATF_Expired,
  740.                                             TAG_DONE);
  741.                }
  742.             }
  743.          }
  744.  
  745.       /* HoldDays auswerten:
  746.          date = Sekunden seit 1.1.1978 des heutigen Tages minus HoldDays
  747.                 (time() liefert Sekunden seit 1.1.1970! -> 8 Jahre abziehen) */
  748.  
  749.       if(apoint->AreaData.HoldDays)
  750.          {
  751.          LONG date = time(NULL) - (LONG)apoint->AreaData.HoldDays * 24L * 3600L;
  752.          /* 8 * 365 Tage + 2 Schalttage zusätzlich abziehen */
  753.          date = date - (3600L * 24L * 365L * 8L) - (3600L * 24L * 2L);
  754.          if(date < 0)
  755.             date = 0;
  756.  
  757.          /* Zurücksetzen Merker-Flag Local 3 */
  758.  
  759.          UMSSelectTags(SysUMSAccount, UMSTAG_SelReadLocal,  TRUE,
  760.                                       UMSTAG_SelMask,       (1L<<3),
  761.                                       UMSTAG_SelMatch,      (1L<<3),
  762.                                       UMSTAG_SelWriteLocal, TRUE,
  763.                                       UMSTAG_SelUnset,      (1L<<3),
  764.                                       TAG_DONE);
  765.  
  766.          /* Local 3 setzen bei allen schon expirierten Msgs */
  767.  
  768.          UMSSelectTags(SysUMSAccount, UMSTAG_SelReadGlobal, TRUE,
  769.                                       UMSTAG_SelMask,       UMSGSTATF_Expired,
  770.                                       UMSTAG_SelMatch,      UMSGSTATF_Expired,
  771.                                       UMSTAG_SelWriteLocal, TRUE,
  772.                                       UMSTAG_SelSet,        (1L<<3),
  773.                                       TAG_DONE);
  774.  
  775.          /* Local 3 setzen bei allen Msgs, die jünger als date sind */
  776.  
  777.          UMSSelectTags(SysUMSAccount, UMSTAG_SelDate,        date,
  778.                                       UMSTAG_SelWriteLocal,  TRUE,
  779.                                       UMSTAG_SelSet,         (1L<<3),
  780.                                       TAG_DONE);
  781.  
  782.          /* Bei allen älteren Msgs in akt. Brett Expired-Flag setzen */
  783.  
  784.          del +=
  785.          UMSSelectTags(SysUMSAccount, UMSTAG_SelReadLocal,   TRUE,
  786.                                       UMSTAG_SelMask,        (1L<<2)|(1L<<3),
  787.                                       UMSTAG_SelMatch,       (1L<<2),
  788.                                       UMSTAG_SelWriteGlobal, TRUE,
  789.                                       UMSTAG_SelSet,         UMSGSTATF_Expired,
  790.                                       TAG_DONE);
  791.          }
  792.  
  793.       if(out)
  794.          {
  795.          sprintf(buff, "%-30.30s (Num:%4d/Days:%3d/Curr:%4d/Prot:%4d) -> -%4d\r\n", strlen(apoint->AreaData.MBName) ? apoint->AreaData.MBName : (STRPTR)"-Mail-", apoint->AreaData.HoldNum, apoint->AreaData.HoldDays, count, arch, del);
  796.          Write(out, buff, strlen(buff));
  797.          }
  798.  
  799.       /* Weiter mit nächstem Brett */
  800.  
  801.       apoint = apoint->Node.mln_Succ;
  802.       }
  803.  
  804.    DropASem();
  805.  
  806.    UMSMsgNum sum =
  807.    UMSSelectTags(SysUMSAccount, UMSTAG_SelReadGlobal, TRUE,
  808.                                 UMSTAG_SelMask,       UMSGSTATF_Expired,
  809.                                 UMSTAG_SelMatch,      UMSGSTATF_Expired,
  810.                                 TAG_DONE);
  811.  
  812.    if(out)
  813.       {
  814.       sprintf(buff, "%79s\r\n%74s%5ld\r\n\r\n", "=====", " => ", sum);
  815.       Write(out, buff, strlen(buff));
  816.       }
  817.  
  818.    sprintf(buff, "%ld", sum);
  819.    RexxOK(buff, NULL);
  820.    }
  821.  
  822. ///
  823.  
  824. /***************************************
  825.  * Rexx-Kommando "REFRESH"             *
  826.  ***************************************
  827.  * I: RexxMsg, Parameterstring, Args   *
  828.  * O: ---                              *
  829.  ***************************************/
  830.  
  831. /// "Rexx_REFRESH"
  832.  
  833. /* SYSTEM/S,ALL/S,UMSGLOBAL/S */
  834.  
  835. VOID Rexx_REFRESH(struct RexxMsg *msg, LONG rxargv[])
  836.    {
  837.    BOOL system = FALSE;
  838.  
  839.    if(rxargv[0]) /* SYSTEM/S */
  840.       system = TRUE;
  841.    else if(rxargv[1]) /* ALL/S */
  842.       system = TRUE;
  843.    else if(rxargv[2]) /* UMSGLOBAL/S */
  844.       SendPortCmd("REFRESH UMS");
  845.  
  846.    if(system)
  847.       {
  848.       // Systemdaten neu einlesen
  849.  
  850.       TEXT dos[LEN_DOSPATH+1];
  851.       TEXT buff[LEN_NUMBER+LEN_ACCBITNAME+2];
  852.       UWORD n;
  853.       FILE *datei;
  854.  
  855.       strcpy(dos, KMSBase->DatDir);
  856.       strcat(dos, "KMS_SYSTEM.DAT");
  857.  
  858.       if(datei = fopen(dos, "r"))
  859.          {
  860.          fgets(buff, LEN_NUMBER+2, datei);
  861.          KMSBase->SystemStartups = atol(buff) + 1;
  862.  
  863.          for(n = 0; n < 32; n++)
  864.             {
  865.             *buff = '\0';
  866.             if(fgets(buff, LEN_ACCBITNAME+2, datei))
  867.                buff[strlen(buff)-1] = '\0';
  868.  
  869.             if(!strlen(buff))
  870.                sprintf(KMSBase->AccBitNames[n], "[Bit#%02d]", n+1);
  871.             else
  872.                strcpy(KMSBase->AccBitNames[n], buff);
  873.             }
  874.  
  875.          fclose(datei);
  876.          }
  877.       else
  878.          {
  879.          KMSBase->SystemStartups = 1;
  880.  
  881.          for(n = 0; n < 32; n++)
  882.             sprintf(KMSBase->AccBitNames[n], "[Bit#%02d]", n+1);
  883.          }
  884.       }
  885.    }
  886.  
  887. ///
  888.  
  889. /************************************
  890.  * Rexx-Msg an alle Ports           *
  891.  ************************************
  892.  * I: Rexx-Cmd                      *
  893.  * O: ---                           *
  894.  ************************************/
  895.  
  896. /// "SendPortCmd"
  897.  
  898. VOID SendPortCmd(STRPTR command)
  899.    {
  900.    TEXT target[LEN_NUMBER+4+1];
  901.  
  902.    TakeMSem(FALSE);
  903.  
  904.    struct KMSNode *member = KMSBase->MemberList.mlh_Head;
  905.    while(member->Node.mln_Succ)
  906.       {
  907.       sprintf(target, "KMS.%d", member->LCPtr->ID);
  908.       sendRexxCmd(command, NULL, NULL, NULL, NULL, target);
  909.  
  910.       member = member->Node.mln_Succ;
  911.       }
  912.  
  913.    DropMSem();
  914.    }
  915.  
  916. ///
  917.  
  918. /***************************************
  919.  * REXX-Kommando-Parser                *
  920.  ***************************************
  921.  * I: STRPTR parsepuff, UBYTE *argc,   *
  922.  * I: STRPTR argv[]                    *
  923.  * O: ---                              *
  924.  ***************************************/
  925.  
  926. /// "RexxCmdParse"
  927.  
  928. VOID RexxCmdParse(STRPTR parsepuff, UBYTE *argc, STRPTR argv[])
  929.    {
  930.    UWORD inzeig = 0;
  931.    UWORD anfang = 0;
  932.    TEXT c;
  933.  
  934.    if(*argc > 0)
  935.       {
  936.       /* Token freigeben */
  937.  
  938.       for(inzeig = 0; inzeig < *argc; inzeig++)
  939.          free(argv[inzeig]);
  940.  
  941.       return;
  942.       }
  943.  
  944.    if(!parsepuff)
  945.       return;
  946.  
  947.    /* Hier geht die Parserei los */
  948.  
  949.    *argc = 0;
  950.  
  951.    while(parsepuff[inzeig] == ' ' || parsepuff[inzeig] == ',')
  952.       inzeig++;
  953.  
  954.    do
  955.       {
  956.       if(parsepuff[inzeig] == '"')
  957.          {
  958.          inzeig++;
  959.          anfang = inzeig;
  960.          while((c = parsepuff[inzeig]) != '"' && c != '\0')
  961.             inzeig++;
  962.          }
  963.       else if(parsepuff[inzeig] == '\'')
  964.          {
  965.          inzeig++;
  966.          anfang = inzeig;
  967.          while((c = parsepuff[inzeig]) != '\'' && c != '\0')
  968.             inzeig++;
  969.          }
  970.       else if(*argc == 0 && parsepuff[inzeig] == '@')
  971.          {
  972.          anfang = inzeig;
  973.          inzeig++;
  974.          }
  975.       else
  976.          {
  977.          anfang = inzeig;
  978.          while((c = parsepuff[inzeig]) != ' ' && c != ',' && c != '\0')
  979.             inzeig++;
  980.          }
  981.  
  982.       if(inzeig-anfang >= 0)
  983.          {
  984.          argv[*argc] = (STRPTR)malloc(inzeig-anfang+1);
  985.          if(!argv[*argc])
  986.             {
  987.             RexxErr(ERR_OUT_OF_MEMORY);
  988.             *argc = 0;
  989.             c = '\0';
  990.             }
  991.          else
  992.             {
  993.             strncpy(argv[*argc], &parsepuff[anfang], inzeig-anfang);
  994.             argv[*argc][inzeig-anfang] = '\0';
  995.  
  996.             (*argc)++;
  997.             if(c == '"' || c == '\'')
  998.                inzeig++;
  999.             while((c = parsepuff[inzeig]) == ' ' || c == ',')
  1000.                inzeig++;
  1001.             }
  1002.          }
  1003.       } while(c != '\0' && *argc < MAXCMDARGS);
  1004.    }
  1005.  
  1006. ///
  1007.  
  1008. /***************************************
  1009.  * Stack-Prüfung                       *
  1010.  ***************************************
  1011.  * I: ---                              *
  1012.  * O: TRUE: OK, FALSE: Out Of Memory   *
  1013.  ***************************************/
  1014.  
  1015. /// CheckStack
  1016.  
  1017. BOOL CheckStack(VOID)
  1018.    {
  1019.    struct Task *mytask = FindTask(NULL);
  1020.  
  1021.    if(mytask->tc_SPReg - mytask->tc_SPLower > 1024)
  1022.       return TRUE;
  1023.    else
  1024.       return FALSE;
  1025.    }
  1026.  
  1027. ///
  1028.  
  1029. /***************************************
  1030.  * LocalConfig des Befehlsgebers holen *
  1031.  ***************************************
  1032.  * I: struct RexxMsg *                 *
  1033.  * O: struct LocalConfig *             *
  1034.  ***************************************/
  1035.  
  1036. /// GetKMSLC
  1037.  
  1038. struct LocalConfig *GetKMSLC(struct RexxMsg *msg)
  1039.    {
  1040.    if(!msg->rm_Args[2])
  1041.       return NULL;
  1042.  
  1043.    UWORD id = (UWORD)msg->rm_Args[2];
  1044.  
  1045.    TakeMSem(FALSE);
  1046.  
  1047.    struct KMSNode *member = KMSBase->MemberList.mlh_Head;
  1048.  
  1049.    while(member->Node.mln_Succ)
  1050.       {
  1051.       if(member->LCPtr->ID == id)
  1052.          {
  1053.          DropMSem();
  1054.          return member->LCPtr;
  1055.          }
  1056.  
  1057.       member = member->Node.mln_Succ;
  1058.       }
  1059.  
  1060.    DropMSem();
  1061.  
  1062.    return NULL;
  1063.    }
  1064.  
  1065. ///
  1066.  
  1067. /*******************************************
  1068.  * UMS-MsgBase-Namen global suchen         *
  1069.  *******************************************
  1070.  * I: gesuchte Area                        *
  1071.  * O: AreaNode                             *
  1072.  *******************************************/
  1073.  
  1074. /// AreaSearch
  1075.  
  1076. struct AreaNode *AreaSearch(STRPTR name)
  1077.    {
  1078.    struct AreaNode *apoint;
  1079.  
  1080.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  1081.    while(apoint->Node.mln_Succ)
  1082.       {
  1083.       if(!stricmp(name, apoint->AreaData.MBName))
  1084.          return apoint;
  1085.  
  1086.       apoint = apoint->Node.mln_Succ;
  1087.       }
  1088.  
  1089.    return NULL;
  1090.    }
  1091.  
  1092. ///
  1093.  
  1094. /*******************************************
  1095.  * Member-Semaphore locken                 *
  1096.  *******************************************
  1097.  * I: Exklusiv?                            *
  1098.  * O: ---                                  *
  1099.  *******************************************/
  1100.  
  1101. /// TakeMSem
  1102.  
  1103. VOID TakeMSem(BOOL exclusive)
  1104.    {
  1105.    if(exclusive)
  1106.       ObtainSemaphore(&KMSBase->SaveSem);
  1107.    else
  1108.       ObtainSemaphoreShared(&KMSBase->SaveSem);
  1109.    }
  1110.  
  1111. ///
  1112.  
  1113. /*******************************************
  1114.  * Member-Semaphore freigeben              *
  1115.  *******************************************
  1116.  * I: ---                                  *
  1117.  * O: ---                                  *
  1118.  *******************************************/
  1119.  
  1120. /// DropMSem
  1121.  
  1122. VOID DropMSem(VOID)
  1123.    {
  1124.    ReleaseSemaphore(&KMSBase->SaveSem);
  1125.    }
  1126.  
  1127. ///
  1128.  
  1129. /*******************************************
  1130.  * Area-Semaphore locken                   *
  1131.  *******************************************
  1132.  * I: Exklusiv?                            *
  1133.  * O: ---                                  *
  1134.  *******************************************/
  1135.  
  1136. /// TakeASem
  1137.  
  1138. VOID TakeASem(BOOL exclusive)
  1139.    {
  1140.    if(exclusive)
  1141.       ObtainSemaphore(&KMSBase->AreaSem);
  1142.    else
  1143.       ObtainSemaphoreShared(&KMSBase->AreaSem);
  1144.    }
  1145.  
  1146. ///
  1147.  
  1148. /*******************************************
  1149.  * Area-Semaphore freigeben                *
  1150.  *******************************************
  1151.  * I: ---                                  *
  1152.  * O: ---                                  *
  1153.  *******************************************/
  1154.  
  1155. /// DropASem
  1156.  
  1157. VOID DropASem(VOID)
  1158.    {
  1159.    ReleaseSemaphore(&KMSBase->AreaSem);
  1160.    }
  1161.  
  1162. ///
  1163.